/**
 * Creates a new CanvasPresenter. The canvas presenter is responsible for drawing the mind map onto a
 * canvas view and reacting to user input on the map (e.g. dragging a node, double clicking it etc.)
 * 
 * @constructor
 * @param {mindmaps.EventBus} eventBus
 * @param {mindmaps.CommandRegistry} commandRegistry
 * @param {mindmaps.MindMapModel} mindmapModel
 * @param {mindmaps.CanvasView} view
 * @param {mindmaps.ZoomController} zoomController
 */
mindmaps.CanvasPresenter = function(eventBus, commandRegistry, mindmapModel,
		view, zoomController) {
	var self = this;
	var creator = view.getCreator();

	/**
	 * Initializes this presenter.
	 */
	this.init = function() {
		var editCaptionCommand = commandRegistry
				.get(mindmaps.EditNodeCaptionCommand);
		editCaptionCommand.setHandler(this.editNodeCaption.bind(this));

		var toggleNodeFoldedCommand = commandRegistry
				.get(mindmaps.ToggleNodeFoldedCommand);
		toggleNodeFoldedCommand.setHandler(toggleFold);
	};

	/**
	 * Handles the edit caption command. Tells view to start edit mode for node.
	 * 
	 * @param {mindmaps.Node} node
	 */
	this.editNodeCaption = function(node) {
		if (!node) {
			node = mindmapModel.selectedNode;
		}
		view.editNodeCaption(node);
	};

	/**
	 * Toggles the fold state of a node.
	 * 
	 * @param {mindmaps.Node} node
	 */
	var toggleFold = function(node) {
		if (!node) {
			node = mindmapModel.selectedNode;
		}

		// toggle node visibility
		var action = new mindmaps.action.ToggleNodeFoldAction(node);
		mindmapModel.executeAction(action);
	};

	/**
	 * Tells the view to select a node.
	 * 
	 * @param {mindmaps.Node} selectedNode
	 * @param {mindmaps.Node} oldSelectedNode
	 */
	var selectNode = function(selectedNode, oldSelectedNode) {

		// deselect old node
		if (oldSelectedNode) {
			view.unhighlightNode(oldSelectedNode);
		}
		view.highlightNode(selectedNode);
	};

	// listen to events from view
	/**
	 * View callback: Zoom on mouse wheel.
	 * 
	 * @ignore
	 */
	view.mouseWheeled = function(delta) {
		view.stopEditNodeCaption();

//		if(mindmaps.EDIT){
//                    if (delta > 0) {
//			zoomController.zoomIn();
//                    } else {
//                            zoomController.zoomOut();
//                    }
//                }
	};

	/**
	 * View callback: Attach creator to node if mouse hovers over node.
	 * 
	 * @ignore
	 */
	view.nodeMouseOver = function(node) {
		if ((view.isNodeDragging() || creator.isDragging()) || mindmaps.EDIT == false) {
			
		} else {
                    // Check how many childrens has the node 
                    if(node.children.count < 3 && node.getDepth() < 2 && node.text.caption != 'Nuevo Concepto' && node.text.caption != 'Idea Central'){
                        creator.attachToNode(node);
                    }
                    else{
                        creator.detach();
                    }
		}
	};

	/**
	 * View callback: Attach creator to node if mouse hovers over node caption.
	 * 
	 * @ignore
	 */
	view.nodeCaptionMouseOver = function(node) {
		if ((view.isNodeDragging() || creator.isDragging()) || mindmaps.EDIT == false ) {
			// dont relocate the creator if we are dragging
		} else {
                    // Check how many childrens has the node 
                    if(node.children.count < 3 && node.getDepth() < 2 && node.text.caption != 'Nuevo Concepto' && node.text.caption != 'Idea Central'){
                        creator.attachToNode(node);
                    }
                    else{
                        creator.detach();
                    }
		}
	};

	/**
	 * View callback: Select node if mouse was pressed.
	 * 
	 * @ignore
	 */
	view.nodeMouseDown = function(node) {
		mindmapModel.selectNode(node);
                if(mindmaps.EDIT == true){
                    // Check how many childrens has the node
                    if(node.children.count < 3 && node.getDepth() < 2 && node.text.caption != 'Nuevo Concepto' && node.text.caption != 'Idea Central'){
                        creator.attachToNode(node);
                    }
                    else{
                        creator.detach();
                    }
                }
                else{
                    
                }
		
	};

	// view.nodeMouseUp = function(node) {
	// };

	/**
	 * View callback: Go into edit mode when node was double clicked.
	 * 
	 * @ignore
	 */
	view.nodeDoubleClicked = function(node) {
                view.openNodeWindow(node, view);
                mindmapModel.openWindowNode(node);
//		view.editNodeCaption(node);
	};

	// view.nodeDragging = function() {
	// };

	/**
	 * View callback: Execute MoveNodeAction when node was dragged.
	 * 
	 * @ignore
	 */
	view.nodeDragged = function(node, offset) {
		// view has updated itself

		// update model
		var action = new mindmaps.action.MoveNodeAction(node, offset);
                
                // Guardamos las posiciones en la BD
                moverNodo(node.id, offset.x, offset.y);
		mindmapModel.executeAction(action);
	};

	/**
	 * View callback: Toggle fold mode when fold button was clicked.
	 * 
	 * @ignore
	 */
	view.foldButtonClicked = function(node) {
		toggleFold(node);
	};
        
        /**
	 * View callback: Toggle fold mode when delete button was clicked.
	 * 
	 * @ignore
	 */
	view.deleteButtonClicked = function(node) {
                // select parent if we are deleting a selected node or a descendant
                var selected = mindmapModel.selectedNode;
                var parent = node.parent;
                if (node === selected || node.isDescendant(selected)) {
                        // deselectCurrentNode();
                        mindmapModel.selectNode(parent);
                }

                // update view
                view.deleteNode(node);
                parent.removeChild(node);
                if (parent.isLeaf()) {
                        view.removeFoldButton(parent);
                }
	};
        

	// CREATOR TOOL
	/**
	 * View callback: Return new random color to view when creator tool was
	 * started to drag.
	 * 
	 * @ignore
	 */
	creator.dragStarted = function(node) {
		// set edge color for new node. inherit from parent or random when root
		var color = node.isRoot() ? '#000'
				: node.branchColor;
		return color;
	};

	/**
	 * View callback: Create a new node when creator tool was stopped.
	 * 
	 * @ignore
	 */
	creator.dragStopped = function(parent, offsetX, offsetY, distance) {
		// disregard if the creator was only dragged a bit
		if (distance < 50) {
			return;
		}

		// update the model
		var node = new mindmaps.Node();
		node.branchColor = creator.lineColor;
		node.offset = new mindmaps.Point(offsetX, offsetY);
		// indicate that we want to set this nodes caption after creation
		node.shouldEditCaption = false;
//                view.openNodeWindow(node, view);

		mindmapModel.createNode(node, parent);
	};

	/**
	 * View callback: Change node caption when text change was committed in
	 * view.
	 * 
	 * @ignore
	 * @param {mindmaps.Node} node
	 * @param {String} str
	 */
	view.nodeCaptionEditCommitted = function(node, str) {
		// avoid whitespace only strings
		var str = $.trim(str);
		if (!str) {
			return;
		}

		view.stopEditNodeCaption();
		mindmapModel.changeNodeCaption(node, str);
	};
        
        view.nodeCloseWindow = function(node){
            mindmapModel.closeWindowNode(node);
        }

	this.go = function() {
		view.init();
	};

	/**
	 * Draw the mind map on the canvas.
	 * 
	 * @param {mindmaps.Document} doc
	 */
	function showMindMap(doc) {
		view.setZoomFactor(zoomController.DEFAULT_ZOOM);
		var dimensions = doc.dimensions;
		view.setDimensions(dimensions.x, dimensions.y);
		var map = doc.mindmap;
		view.drawMap(map);
		view.center();

		mindmapModel.selectNode(map.root);
	}

	/**
	 * Hook up with EventBus.
	 */
	function bind() {
		// listen to global events
		eventBus.subscribe(mindmaps.Event.DOCUMENT_OPENED, function(doc,
				newDocument) {
			showMindMap(doc);

			// if (doc.isNew()) {
			// // edit root node on start
			// var root = doc.mindmap.root;
			// view.editNodeCaption(root);
			// }
		});

		eventBus.subscribe(mindmaps.Event.DOCUMENT_CLOSED, function(doc) {
			view.clear();
		});

		eventBus.subscribe(mindmaps.Event.NODE_MOVED, function(node) {
			view.positionNode(node);
		});

		eventBus.subscribe(mindmaps.Event.NODE_TEXT_CAPTION_CHANGED, function(
				node) {
			view.setNodeText(node, node.getCaption());

			// redraw node in case height has changed
			// TODO maybe only redraw if height has changed
			view.redrawNodeConnectors(node);
		});

		eventBus.subscribe(mindmaps.Event.NODE_CREATED, function(node) {
			view.createNode(node);

			// edit node caption immediately if requested
			if (node.shouldEditCaption) {
				delete node.shouldEditCaption;
				// open parent node when creating a new child and the other
				// children are hidden
				var parent = node.getParent();
				if (parent.foldChildren) {
					var action = new mindmaps.action.OpenNodeAction(parent);
					mindmapModel.executeAction(action);
				}

				// select and go into edit mode on new node
				mindmapModel.selectNode(node);
				// attach creator manually, sometimes the mouseover listener wont fire
				creator.attachToNode(node);
				view.editNodeCaption(node);
			}
		});

		eventBus.subscribe(mindmaps.Event.NODE_DELETED, function(node, parent) {
			// select parent if we are deleting a selected node or a descendant
			var selected = mindmapModel.selectedNode;
			if (node === selected || node.isDescendant(selected)) {
				// deselectCurrentNode();
				mindmapModel.selectNode(parent);
			}

			// update view
			view.deleteNode(node);
			if (parent.isLeaf()) {
				view.removeFoldButton(parent);
			}
		});

		eventBus.subscribe(mindmaps.Event.NODE_SELECTED, selectNode);
		
		eventBus.subscribe(mindmaps.Event.NODE_OPENED, function(node) {
			view.openNode(node);
		});
		eventBus.subscribe(mindmaps.Event.NODE_CLOSED, function(node) {
			view.closeNode(node);
		});
		eventBus.subscribe(mindmaps.Event.NODE_FONT_CHANGED, function(node) {
			view.updateNode(node);
		});
		eventBus.subscribe(mindmaps.Event.NODE_BRANCH_COLOR_CHANGED, function(
				node) {
			view.updateNode(node);
		});
		eventBus.subscribe(mindmaps.Event.ZOOM_CHANGED, function(zoomFactor) {
			view.setZoomFactor(zoomFactor);
			view.applyViewZoom();
			view.scaleMap();
		});
	}

	bind();
	this.init();
};